/**
 * Project Name:nplus1
 * File Name:RestapiClientSignValidator.java
 * Package Name:com.gamma.nplus1.common.utils.sign
 * Date:2017年5月19日下午3:57:17
 * Copyright (c) 2017, nplus1 Co., Ltd. All Rights Reserved.
 *
*/

package com.gamma.nplus1.common.utils.sign;

import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

/**
 * ClassName:RestapiSignProcessor <br/>
 * Function: rest api client 签名验证器. <br/>
 * Date:     2017年5月19日 下午3:57:17 <br/>
 * @author   jeno
 * @version  
 * @since    JDK 1.7
 */
public class RestapiSignProcessor {

	public static final String ACCESS_APP_ID = "appId";
	public static final String ACCESS_SIGNATURE = "signature";
	public static final String ACCESS_RAND_STR = "randStr";
	public static final String ACCESS_TIMESTRAP = "timestrap";
    
    private String accessKey;
    private SecretKeySpec secretKey;

    /**
     * auth
     * 
     * @param accessKey
     *            appid
     * @param secretKeySpec
     *            appsecret
     */
    public RestapiSignProcessor(String accessKey, String secretKey) {
        if (StringUtils.isNullOrEmpty(accessKey) || StringUtils.isNullOrEmpty(secretKey)) {
            throw new IllegalArgumentException("empty key");
        }
        byte[] sk = StringUtils.utf8Bytes(secretKey);
        SecretKeySpec secretKeySpec = new SecretKeySpec(sk, "HmacSHA1");
        
        this.accessKey = accessKey;
        this.secretKey = secretKeySpec;
    }

    /**
     * 格式化参数，签名过程需要使用
     * 
     * @return
     */
    public String formatParamsMap(StringMap params) {
        //初始化返回值
        StringBuilder rtn = new StringBuilder();
        
        //取得params keys
        Set<String> keys = params.keyset();

        //排序列表
        List<String> listKeys = new ArrayList<String>(keys);

        //排序
        Collections.sort(listKeys);

        //组织格式化字符串
        for (String key : listKeys) {
            if(ACCESS_SIGNATURE.equals(key)) {
                continue;
            }
            
            rtn.append(key);
            rtn.append("=");
            rtn.append(params.get(key)==null ? "":params.get(key).toString());
            rtn.append("&");
        }

        //remove last &
        String strRtn = rtn.toString();
        
        if (strRtn.length()>0) {
            strRtn = strRtn.substring(0, strRtn.length() - 1);
        }
        
        return strRtn.toString();
    }
    
    private Mac createMac() {
        Mac mac;
        try {
            mac = javax.crypto.Mac.getInstance("HmacSHA1");
            mac.init(secretKey);
        } catch (GeneralSecurityException e) {
            e.printStackTrace();
            throw new IllegalArgumentException(e);
        }
        return mac;
    }
    
    /**
     * 参数签名
     * @param data
     * @return
     */
    public String sign(byte[] data) {
        Mac mac = createMac();
        String encodedSign = UrlSafeBase64.encodeToString(mac.doFinal(data));
        return this.accessKey + ":" + encodedSign;
    }

    /**
     * 参数签名
     * @param data
     * @return
     */
    public String sign(String data) {
        return sign(StringUtils.utf8Bytes(data));
    }
    
    /**
     * 参数签名
     * @param data
     * @return
     */
    public String sign(StringMap data) {
        String formatstr = this.formatParamsMap(data);
        return sign(StringUtils.utf8Bytes(formatstr));
    }
}

